/**
 * @file spc_list.h
 * @author your name (you@domain.com)
 * @brief 单生产者消费者队列, 一个线程生产数据另一个线程消费数据
 * @version 0.1
 * @date 2024-02-28
 *
 * @copyright Copyright (c) 2024
 *
 */

/*
 * 仅在 单生产者单消费者模式下,线程安全, 其他多线程情况不适用
 */

#pragma once

#include <atomic>
#include <memory>

namespace wheels {

template <typename T>
class SpcList {
    struct node {
        std::shared_ptr<T> data;
        std::unique_ptr<node> next;
    };

   public:
    SpcList() : header_(std::make_unique<node>()), tail_(header_.get()) {}

    SpcList(const SpcList &) =delete;
    SpcList &operator=(const SpcList &) =delete;

    inline bool Empty() { return header_.get() == tail_.load(); }

    void Push(T v) {
        auto new_val = std::make_shared<T>(std::move(v));
        auto new_node = std::make_unique<node>();
        node *tail_point = tail_.load();
        tail_point->next = std::move(new_node);
        tail_point->data = new_val;
        tail_.store(tail_point->next.get());
        // tail_ = tail_point->next.get();
    }

    std::shared_ptr<T> Pop() {
        if (Empty()) {
            return nullptr;
        }

        auto tmp = std::move(header_);
        header_ = std::move(tmp->next);
        return tmp->data;
    }

   private:
    std::unique_ptr<node> header_;
    std::atomic<node *> tail_;
    // node * tail_;
};

}  // namespace wheels
